package org.hit.burkun.umls;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.hit.burkun.db.DBHelper;
import org.hit.burkun.db.DBTypeConverter;
import org.hit.burkun.db.DBTypeConverter.DATATYPE;
import org.hit.burkun.entities.Entity;
import org.hit.burkun.util.GlobalData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 这个类要做的是提供一个统一的导入数据库的工具
 * 
 * @author burkun
 * 
 */
public class MapidsUmlsDump {
	// 全局唯一NC，ID
	private static int counter = getCurCounter();

	private static Logger logger = LoggerFactory
			.getLogger(MapidsUmlsDump.class);

	private DBHelper dbh;
	private String[] insertFileds = { "umls_cui", "db_id", "db_type",
			"is_mapped", "map_path" };
	private DBTypeConverter dataTypesCovert;
	private String tbName;

	public MapidsUmlsDump(DBHelper dbh, String tbName) {
		this.dbh = dbh.clone();
		this.tbName = tbName;

		DATATYPE[] dataTypes = new DATATYPE[insertFileds.length];
		dataTypes[3] = DATATYPE.I;

		dataTypesCovert = new DBTypeConverter(dataTypes);
	}

	public void updateUmlsByMapedData(Entity.TYPE type,
			Map<String, Set<String>> data, String mapPath) {
		// 删除当前的
		deleteUnmapped(data.keySet(), type);
		// 插入新增的
		saveMappedToDb(type, data, mapPath);
	}

	// 先删除，再插入
	private void deleteUnmapped(Collection<String> ids, Entity.TYPE type) {
		logger.debug("delete unmaped from db " + tbName + "...");
		String updateStr = "delete from " + tbName
				+ " where db_id in (%s) and is_mapped = 0 and db_type = '"
				+ type.getTag() + "'";
		int counter = 0;
		int maxCounter = 200;
		StringBuilder sb = new StringBuilder();
		dbh.connectionDB();
		for (String id : ids) {
			counter += 1;
			sb.append("'" + id + "',");
			if (counter == maxCounter) {
				sb.deleteCharAt(sb.length() - 1);
				String sqlTempl = String.format(updateStr, sb.toString());
				sb.setLength(0);
				counter = 0;
				dbh.exec(sqlTempl);
			}
		}
		if (counter > 0) {
			sb.deleteCharAt(sb.length() - 1);
			String sqlTempl = String.format(updateStr, sb.toString());
			sb.setLength(0);
			counter = 0;
			dbh.exec(sqlTempl);
		}
		dbh.disconnection();
	}

	/**
	 * maped id from source
	 * 
	 * @param data
	 */
	public void saveMappedToDb(Entity.TYPE type, Map<String, Set<String>> data) {
		/*
		 * CREATE TABLE `map_ids` ( `primary_id` int(11) NOT NULL
		 * AUTO_INCREMENT, `umls_cui` varchar(45) DEFAULT NULL, `db_id`
		 * varchar(255) DEFAULT NULL, `db_type` varchar(45) DEFAULT NULL,
		 * `is_mapped` int(1) DEFAULT '1', `map_path` text, PRIMARY KEY
		 * (`primary_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
		 */
		saveMappedToDb(type, data, type.getTag() + "=>" + "umls");
	}

	/**
	 * maped id from source
	 * 
	 * @param data
	 */
	public void saveMappedToDb(Entity.TYPE type, Map<String, Set<String>> data,
			String mapPath) {
		/*
		 * CREATE TABLE `map_ids` ( `primary_id` int(11) NOT NULL
		 * AUTO_INCREMENT, `umls_cui` varchar(45) DEFAULT NULL, `db_id`
		 * varchar(255) DEFAULT NULL, `db_type` varchar(45) DEFAULT NULL,
		 * `is_mapped` int(1) DEFAULT '1', `map_path` text, PRIMARY KEY
		 * (`primary_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
		 */
		logger.debug("save mapped data in to " + tbName + "...");
		Set<Entry<String, Set<String>>> enties = data.entrySet();
		LinkedList<String[]> insertData = new LinkedList<String[]>();
		String strType = type.getTag();
		// 加一个判断，
		for (Entry<String, Set<String>> entry : enties) {
			String sourceID = entry.getKey();
			for (String cuis : entry.getValue()) {
				String[] line = new String[insertFileds.length]; // 忽略primary id
				line[0] = cuis;
				line[1] = sourceID;
				line[2] = strType;
				line[3] = isMapped(cuis);
				line[4] = mapPath;
				insertData.add(line);
			}
		}
		dbh.connectionDB();
		logger.debug("data size:" + insertData.size() + "...");
		dbh.insertBatch(tbName, insertFileds, insertData, dataTypesCovert);
		dbh.disconnection();
	}

	private String isMapped(String cui) {
		if (cui == null || cui.length() == 0 || cui.indexOf("UMAP") != -1) {
			return "0";
		}
		return "1";
	}

	/*
	 * unmaped id
	 */
	public Map<String, Set<String>> saveUnMappedToDb(Entity.TYPE type,
			Collection<String> data) {
		if (data.size() > 0) {
			logger.debug("save umapped data in to " + tbName + "...");
			String strType = type.getTag();
			String isMapped = "0";
			LinkedList<String[]> insertData = new LinkedList<String[]>();
			Map<String, Set<String>> returns = new HashMap<String, Set<String>>();
			for (String id : data) {
				String[] line = new String[insertFileds.length]; // 忽略primary id
				line[0] = "NMAP" + (counter++); // 生成非全局的ID，这种mapping不上的就给他们一个全局ID
				line[1] = id;
				line[2] = strType;
				line[3] = isMapped;
				line[4] = null;
				insertData.add(line);
				// 生成映射表
				Set<String> vs = new HashSet<String>();
				vs.add(line[0]);
				returns.put(id, vs);
			}
			dbh.connectionDB();
			dbh.insertBatch(tbName, insertFileds, insertData, dataTypesCovert);
			dbh.disconnection();
			return returns;
		}
		return null;
	}

	// 保存当前的counter
	private static int getCurCounter() {
		return Integer.parseInt(GlobalData.getInstance().getProperties()
				.get("UNMAPINGCOUNTTER").toString());
	}

	private static void setCurCounter() {
		GlobalData.getInstance().setPropertity("UNMAPINGCOUNTTER",
				String.valueOf(counter));
	}

	// 写析构函数
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		setCurCounter();
	}

}
